package tabletask

import (
	"crypto/sha1"
	"encoding/hex"
	"io"
	"io/ioutil"
	"os"
	"time"

	"cvevulner/cve-timed-task/db_models"
	"cvevulner/cve-timed-task/downloadfiletask"
	"cvevulner/cve-timed-task/util"
	"cvevulner/models"
	"github.com/360EntSecGroup-Skylar/excelize/v2"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/orm"
	"github.com/pkg/errors"
)

// ToMysql Data stored in the database
func ToMysql() {
	ormModel := orm.NewOrm()
	filePath, err := downloadfiletask.HandleTwo()
	if err != nil {
		logs.Error("downloadfiletask.HandleTwo error:", err)
		return
	}
	files, rErr := ioutil.ReadDir(filePath)
	if rErr != nil {
		logs.Error(" ioutil.ReadDir error: ", rErr, filePath)
		return
	}

	for _, file := range files {
		fileName := file.Name()
		if file.IsDir() {
			logs.Warn(filePath+fileName, "is Dir, remove")
			_ = os.RemoveAll(filePath + fileName)
			continue
		}
		f, oErr := os.Open(filePath + fileName)
		if oErr != nil {
			logs.Error("oErr:", oErr)
			continue
		}

		hash := sha1.New()
		_, cErr := io.Copy(hash, f)
		if cErr != nil {
			logs.Error("io.Copy :", cErr)
			_ = f.Close()
			continue
		}
		_ = f.Close()

		sum := hash.Sum(nil)
		hashValue := hex.EncodeToString(sum)
		tranErr := ormModel.Begin()
		if tranErr != nil {
			logs.Error(" Open transaction error:", tranErr.Error())
			continue
		}
		list, rowsAffected, hErr := db_models.SelectCveFileHashByFileName(fileName, ormModel)
		if hErr != nil {
			logs.Error("db_models.SelectCveFileHashByFileName, error: ", hErr)
			tranErr = ormModel.Rollback()
			if tranErr != nil {
				logs.Error("Rollback transaction error:", tranErr.Error())
			}
			continue
		}

		if rowsAffected > 0 && util.InSlice(list, hashValue) {
			logs.Info("file has been parsed", fileName)
			tranErr = ormModel.Rollback()
			if tranErr != nil {
				logs.Error("Rollback transaction error:", tranErr.Error())
			}

			_, aErr := os.Stat(beego.AppConfig.String("timedtask::packageDir") + "oldexcels/")
			if aErr != nil {
				logs.Error("os.Stat error:", aErr.Error())
				if os.IsNotExist(aErr) {
					logs.Info("And there is no such directory", filePath, "start to create")
					aErr = os.Mkdir(beego.AppConfig.String("timedtask::packageDir")+"oldexcels/", os.ModePerm)
					if aErr != nil {
						logs.Error("os.Mkdir error:", filePath, aErr.Error())
					}
					logs.Info("create directory success:", filePath)
				}
			}
			aErr = os.Rename(filePath+fileName, beego.AppConfig.String("timedtask::packageDir")+"oldexcels/"+fileName)
			if aErr != nil {
				logs.Error(aErr.Error())
			}
			continue
		}

		err = db_models.InsertCveFileHash(fileName, hashValue, ormModel)
		if err != nil {
			logs.Error("db_models.InsertCveFileHash,error: ", err)
			tranErr = ormModel.Rollback()
			if tranErr != nil {
				logs.Error(" Rollback transaction error:", tranErr.Error())
			}
			continue
		}
		tranErr = ormModel.Commit()
		if tranErr != nil {
			logs.Error(" Commit transaction error:", tranErr.Error())
			continue
		}

		excel, oErr := excelize.OpenFile(filePath + fileName)
		if oErr != nil {
			logs.Error("excelize.OpenReader:", oErr, filePath+fileName)
			continue
		}

		rows, gErr := excel.GetRows("Sheet1")
		if gErr != nil {
			logs.Error("excel.GetRows Sheet1 error: ", gErr)
			continue
		}
		now := time.Now().Format("2006-01-02 15:04:05")
		var packName string
		var cpePackName string
		for _, row := range rows[1:] {
			if len(row) < 1 || row[0] == "" {
				continue
			}
			packName = row[0]

			if len(row) > 1 {
				cpePackName = row[1]
			} else {
				cpePackName = ""
			}

			tranErr = ormModel.Begin()
			if tranErr != nil {
				logs.Error(" Open transaction error:", tranErr.Error())
				continue
			}
			packageCpe, pErr := db_models.SelectCvePackAgeCpeByPackName(packName, ormModel)
			if pErr != nil {
				if errors.Is(orm.ErrNoRows, pErr) {
					pErr = db_models.InsertCvePackAgeCpe(&models.PackageCpe{
						PackName:    packName,
						CpePackName: cpePackName,
						CreateTime:  now,
					}, ormModel)
					if pErr != nil {
						logs.Error("db_models.InsertCvePackAgeCpe error:", pErr)
						tranErr = ormModel.Rollback()
						if tranErr != nil {
							logs.Error(" Rollback transaction error:", tranErr.Error())
						}
						continue
					}
				} else {
					logs.Error("db_models.SelectCvePackAgeCpeByPackName error: ", err)
					tranErr = ormModel.Rollback()
					if tranErr != nil {
						logs.Error(" Rollback transaction error:", tranErr.Error())
					}
					continue
				}
			} else {
				if packageCpe.CpePackName != cpePackName {
					err = db_models.UpdateCvePackAgeCpe(models.PackageCpe{
						CpePackName: cpePackName,
						CreateTime:  now,
						PackName:    packageCpe.PackName,
					}, ormModel)
					if err != nil {
						logs.Error("db_models.UpdateCvePackAgeCpe error:", err)
						tranErr = ormModel.Rollback()
						if tranErr != nil {
							logs.Error(" Rollback transaction error:", tranErr.Error())
						}
						continue
					}
				}
			}
			tranErr = ormModel.Commit()
			if tranErr != nil {
				logs.Error(" Commit transaction error:", tranErr.Error())
				continue
			}
		}
		_, err = os.Stat(beego.AppConfig.String("timedtask::packageDir") + "oldexcels/")
		if err != nil {
			logs.Error("os.Stat error:", err.Error())
			if os.IsNotExist(err) {
				logs.Info("And there is no such directory", filePath, "start to create")
				err = os.Mkdir(beego.AppConfig.String("timedtask::packageDir")+"oldexcels/", os.ModePerm)
				if err != nil {
					logs.Error("os.Mkdir error:", filePath, err.Error())
				}
				logs.Info("create directory success:", filePath)
			}
		}
		err = os.Rename(filePath+fileName, beego.AppConfig.String("timedtask::packageDir")+"oldexcels/"+fileName)
		if err != nil {
			logs.Error(err.Error())
		}
		continue
	}
}
